package net.vinote.sosa.context.support;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

public class SosaResource {
	private VelocityContext context = new VelocityContext();
	private boolean init = false;
	private DefaultResourceLoader loader;

	public SosaResource(DefaultResourceLoader loader) {
		this.loader = loader;
	}

	public void init(Resource sosaResource) throws IOException {
		if (!init) {
			Velocity.init();
			Properties properties = new Properties();
			properties.load(sosaResource.getInputStream());
			for (Entry<Object, Object> entry : properties.entrySet()) {
				context.put(entry.getKey().toString(), entry.getValue());
			}
			init = true;
		}
	}

	public Resource[] getResources(String locationPattern, Resource[] resources) {
		if (ArrayUtils.isEmpty(resources)
				|| !StringUtils.endsWith(locationPattern, ".xml")) {
			return resources;
		}
		Resource[] proxys = new Resource[resources.length];
		for (int i = 0; i < resources.length; i++) {
			proxys[i] = getProxyResource(resources[i]);
		}
		return proxys;
	}

	public Resource getProxyResource(final Resource resource) {
		return (Resource) Proxy.newProxyInstance(loader.getClassLoader(),
				new Class[] { Resource.class }, new InvocationHandler() {
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						if (StringUtils.equals(method.getName(),
								"getInputStream")) {
							StringWriter writer = new StringWriter();
							Velocity.evaluate(context, writer, resource
									.getURI().toString(),
									new BufferedReader(new InputStreamReader(
											resource.getInputStream())));
							return new ByteArrayInputStream(writer.toString()
									.getBytes());
						} else {
							return method.invoke(resource, args);
						}
					}
				});
	}

	/**
	 * Getter method for property <tt>init</tt>.
	 *
	 * @return property value of init
	 */
	public final boolean isInit() {
		return init;
	}

}
